pub mod codec;

use std::{future::Future, net::SocketAddr};
use tokio::{
    io::{AsyncRead, AsyncWrite},
    net::{TcpListener, TcpStream},
};

pub trait ConnectionSource {
    type Conn: AsyncRead + AsyncWrite;
    type OtherEndInfo;
    type Err: Into<std::io::Error>;

    fn get_one(
        &self,
    ) -> impl Future<Output = Result<(Self::Conn, Self::OtherEndInfo), Self::Err>> + Send;
}

pub struct TcpConnectionStream(pub TcpListener);
impl ConnectionSource for TcpConnectionStream {
    type Conn = TcpStream;
    type OtherEndInfo = SocketAddr;
    type Err = std::io::Error;

    fn get_one(
        &self,
    ) -> impl Future<Output = Result<(Self::Conn, Self::OtherEndInfo), Self::Err>> + Send {
        self.0.accept()
    }
}

#[cfg(feature = "tls-rustls")]
pub mod tls_rustls {
    pub use tokio_rustls;

    use super::ConnectionSource;
    use std::{net::SocketAddr, future::Future};
    use tokio::net::{TcpStream, TcpListener};
    use tokio_rustls::{server::TlsStream, TlsAcceptor};

    pub struct TlsTcpConnectionStream(pub TcpListener, pub TlsAcceptor);
    impl ConnectionSource for TlsTcpConnectionStream {
        type Conn = TlsStream<TcpStream>;
        type OtherEndInfo = SocketAddr;
        type Err = std::io::Error;

        fn get_one(
            &self,
        ) -> impl Future<Output = Result<(Self::Conn, Self::OtherEndInfo), Self::Err>> + Send
        {
            async move {
                let (tcp_conn, addr) = self.0.accept().await?;
                self.1.accept(tcp_conn).await.map(|conn| (conn, addr))
            }
        }
    }
}
